package com.polito.mad.bikeponyapp.activity;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.polito.mad.bikeponyapp.R;
import com.polito.mad.bikeponyapp.persistence.Question;
import com.polito.mad.bikeponyapp.persistence.QuestionDao;
import com.polito.mad.bikeponyapp.persistence.QuestionsRepository;
import com.polito.mad.bikeponyapp.util.AgentState;
import com.polito.mad.bikeponyapp.util.ResultMessage;

/**
 * Activity which displays a login screen to the user, offering registration as
 * well.
 */
public class LoginActivity extends Activity {

	/**
	 * Keep track of the login task to ensure we can cancel it if requested.
	 */
	private UserLoginTask mAuthTask = null;

	// Values for email and password at the time of the login attempt.
	private String mUserId;
	private String mPassword;

	// UI references.
	private EditText mUserIdView;
	private EditText mPasswordView;
	private View mLoginFormView;
	private View mLoginStatusView;
	private TextView mLoginStatusMessageView;

	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		
		setContentView(R.layout.activity_login);

		SharedPreferences sh = PreferenceManager.getDefaultSharedPreferences(this);
		// Set up the login form.
		mUserId = sh.getString(getString(R.string.userid_pref), "");
		mPassword = sh.getString(getString(R.string.password_pref), "");
		
		mUserIdView = (EditText) findViewById(R.id.userId);
		mUserIdView.setText(mUserId);
		mPasswordView = (EditText) findViewById(R.id.password);
		mPasswordView.setText(mPassword);
		
		mPasswordView.setOnEditorActionListener(
			new TextView.OnEditorActionListener() {
				@Override
				public boolean onEditorAction(TextView textView, int id,KeyEvent keyEvent) {
					if (id == R.id.login || id == EditorInfo.IME_NULL) {
						attemptLogin();
						return true;
					}
					return false;
				}
			});

		mLoginFormView = findViewById(R.id.login_form);
		mLoginStatusView = findViewById(R.id.login_status);
		mLoginStatusMessageView = (TextView) findViewById(R.id.login_status_message);

		findViewById(R.id.sign_in_button).setOnClickListener(
			new View.OnClickListener() {
				@Override
				public void onClick(View view) {
					view.requestFocus();
					hideSoftKeyboard();
					attemptLogin();
				}
			});
		getActionBar().setDisplayShowTitleEnabled(true);
		getActionBar().setTitle("BIKE PONY");
		if(!mUserId.equals("") && !mPassword.equals(""))
			attemptLogin();
		
		
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		getMenuInflater().inflate(R.menu.login, menu);
		return false;
	}

	@Override
	protected void onStart() {
		super.onStart();
		
		Intent receivedIntent = getIntent();
		if(receivedIntent !=null && receivedIntent.getAction()!=null && receivedIntent.getAction().equals(MainActivity.LOGOUT_ACTION))
		{
			Toast.makeText(this, "You are succesfully Logged off", Toast.LENGTH_LONG).show();
		}
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) 
	{
		if(item.getItemId() == R.id.action_help)
		{
			Intent i = new Intent(getApplicationContext(),HelpActivity.class);
			startActivity(i);
		}
		
		return super.onOptionsItemSelected(item);
	}
	
	/**
	 * Attempts to sign in or register the account specified by the login form.
	 * If there are form errors (invalid email, missing fields, etc.), the
	 * errors are presented and no actual login attempt is made.
	 */
	public void attemptLogin() {
		
		if (mAuthTask != null) {
			return;
		}

		// Reset errors.
		mUserIdView.setError(null);
		mPasswordView.setError(null);

		// Store values at the time of the login attempt.
		mUserId = mUserIdView.getText().toString();
		mPassword = mPasswordView.getText().toString();

		boolean cancel = false;
		View focusView = null;

		// Check for a valid password.
		if (TextUtils.isEmpty(mPassword)) {
			mPasswordView.setError(getString(R.string.error_field_required));
			focusView = mPasswordView;
			cancel = true;
		} else if (mPassword.length() < 4) {
			mPasswordView.setError(getString(R.string.error_invalid_password));
			focusView = mPasswordView;
			cancel = true;
		}

		// Check for a valid userId .
		if (TextUtils.isEmpty(mUserId)) {
			mUserIdView.setError(getString(R.string.error_field_required));
			focusView = mUserIdView;
			cancel = true;
		}

		if (cancel) {
			// There was an error; don't attempt login and focus the first
			// form field with an error.
			focusView.requestFocus();
		} else {
			// Show a progress spinner, and kick off a background task to
			// perform the user login attempt.
			mLoginStatusMessageView.setText(R.string.login_progress_signing_in);
			mAuthTask = new UserLoginTask();
			mAuthTask.execute();
		}
	}

	private void showProgress(final boolean show)
	{
		mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE);
		mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
	}
	
	
	private void setAgentStatusPref(AgentState agentState) {
		
		SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
		Editor editor = pref.edit();
		editor.putString(getString(R.string.userid_pref), mUserId);
		editor.putString(getString(R.string.password_pref), mPassword);
		editor.putInt(getString(R.string.user_status_pref), agentState.getState());
		editor.commit();
	}
	
	private class UserLoginTask extends AsyncTask<Void, Void, ResultMessage>
	{
		private String userId;
		private String password;
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			this.userId= mUserId;
			this.password=mPassword;
			showProgress(true);
			CookieHandler.setDefault(new CookieManager());
		}
		
		@Override
		protected ResultMessage doInBackground(Void... params) {
			StringBuilder b = new StringBuilder();
			b.append(getString(R.string.server_com_protocol))
			.append("://")
			.append(getString(R.string.server_host))
			.append(":")
			.append(getString(R.string.server_port))
			.append(getString(R.string.server_services_context_path))
			.append(getString(R.string.server_services_agent_path))
			.append(getString(R.string.server_services_agent_login));
			
			ResultMessage resultMessage=null;
			if(!isNetworkAvailable())
			{
				resultMessage = new ResultMessage(-1, getString(R.string.error_network_not_connected) );
				return resultMessage;
			}
			
			try {
				InputStream is =null;
				URL url_ = new URL(b.toString());
				b=null;
				HttpURLConnection connection = (HttpURLConnection) url_.openConnection();
				connection.setDoInput(true);
				connection.setDoOutput(true);
				
				connection.setAllowUserInteraction(true);
				connection.setConnectTimeout(60000);//60 seconds 
				connection.connect();
				
				b = new StringBuilder().append("agentId=").append(userId).append("&password=").append(password);
				
				OutputStream os = connection.getOutputStream();
				if(os!=null)
				{
					BufferedOutputStream bos = new BufferedOutputStream(os);
					bos.write(b.toString().getBytes());
					bos.close();
					is = connection.getInputStream();
				}
				
				if(is!=null)
				{
					BufferedReader br = new BufferedReader(new InputStreamReader(is));
					String line = null;
					b = new StringBuilder();
					while((line = br.readLine())!=null)
						b.append(line);
					
					JSONObject result = new JSONObject(b.toString());
					resultMessage = new ResultMessage(result);
	
					if(result!=null)
					switch(resultMessage.getStatusCode())
					{
						case ResultMessage.STATUS_OK:
							/*update the UI agent icon status to logged in */
							
							/*the result message should contain the questions, check if it is true*/
							try
							{
								QuestionsRepository repos = new QuestionsRepository(LoginActivity.this);
								JSONArray questions = resultMessage.getData().getJSONArray("questions");
								List<Question> questionsToAdd = new ArrayList<Question>();
								for(int i=0;i<questions.length();i++)
								{
									JSONObject question = questions.getJSONObject(i);
									long qId = question.getLong("id");
									String text = question.getString("text");

										Question q = new Question();
										q.setText(text);
										q.setQuestionId(qId);
										List<Question> existingQuestions = repos.findByQuery(QuestionDao.QUESTION_ID_INDEX+" = "+qId);
										if(existingQuestions==null || existingQuestions.isEmpty())
											questionsToAdd.add(q);												
								}
								if(!questionsToAdd.isEmpty())
								{
									int size = questionsToAdd.size();
									int newSze = repos.addAll(questionsToAdd).size();
									if(size!=newSze)
									{
										throw new Exception("invalid operation during questions save ");
									}
								}
								repos.close();
								repos=null;
							}
							catch(JSONException je){
								je.printStackTrace();
							} catch (Exception e) {
								e.printStackTrace();
							}
							/*remove the LOGOUT button from the drawer panel and from any other menus*/
					}
					
				}
			}
			catch(UnknownHostException excp)
			{
				excp.printStackTrace();
				resultMessage = new ResultMessage(-1, getString(R.string.error_server_not_responding));
			}
			catch(ConnectException excp)
			{
				excp.printStackTrace();
				resultMessage = new ResultMessage(-1, getString(R.string.error_server_not_responding));
			}catch(IOException ie)
			{
				ie.printStackTrace();
				resultMessage = new ResultMessage(-1,getString(R.string.error_server_not_responding));
			} catch (JSONException e1) {
				resultMessage = new ResultMessage(-1, getString(R.string.error_application_connection));
			}
			return resultMessage;
			
		}
		@Override
		protected void onPostExecute(ResultMessage result) {
			super.onPostExecute(result);
			mAuthTask = null;
			
			if(result==null)
			{
				showProgress(false);
				Toast.makeText(getApplicationContext(), getString(R.string.error_network_connection), Toast.LENGTH_LONG).show();
				mUserIdView.requestFocus();
				return;
			}
			switch(result.getStatusCode())
			{
				case ResultMessage.STATUS_OK:
					setAgentStatusPref(AgentState.STATUS_LOGGED_IN);
					
					PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
					.edit()
					.putBoolean(getString(R.string.login_performed), true)
					.commit();
					
					Intent startMainActivityIntent = new Intent(getApplicationContext(),MainActivity.class);
					startMainActivityIntent.putExtras(new Bundle());
					startMainActivityIntent.getExtras().putString("message", getString(R.string.login_successful));
					startMainActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
					startActivity(startMainActivityIntent);
					
					finish();
				break;
				case ResultMessage.STATUS_ERR_ALREADY_LOGGED_IN:
					
					setAgentStatusPref(AgentState.STATUS_LOGGED_IN);
					setLoginPerformedPref(true);
					
					startMainActivityIntent = new Intent(getApplicationContext(),MainActivity.class);
					startMainActivityIntent.putExtras(new Bundle());
					startMainActivityIntent.getExtras().putString("message", getString(R.string.login_failed)+result.getMessage());
					
					startMainActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
					startActivity(startMainActivityIntent);
					
					finish();
					
				break;
				case ResultMessage.STATUS_ERR_UNKNOWN:
					showProgress(false);
					setLoginPerformedPref(false);
					Toast.makeText(getApplicationContext(), getString(R.string.login_failed)+" " +result.getMessage(), Toast.LENGTH_LONG).show();
					mUserIdView.requestFocus();
				break;
				case ResultMessage.STATUS_ERR_INVALID_CREDENTIALS:
					showProgress(false);
					setLoginPerformedPref(false);
					mPasswordView.setError(getString(R.string.error_incorrect_password));
					mUserIdView.setError(getString(R.string.error_incorrect_userId));
					mUserIdView.requestFocus();
				default:
			}
		}
		
		public void setLoginPerformedPref(boolean loginPerformed)
		{
			PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
			.edit()
			.putBoolean(getString(R.string.login_performed), loginPerformed)
			.commit();
		}
	}
	private void hideSoftKeyboard(){
		if(getCurrentFocus()!=null && getCurrentFocus() instanceof EditText){
			InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
			imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
		}
	}
	
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		
		/*Text Boxes automatically save and restore their values , so we avoid saving them inside the instanceState*/
	}
	
	private boolean isNetworkAvailable() {
	    ConnectivityManager connectivityManager 
	          = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
	    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
	    return activeNetworkInfo != null && activeNetworkInfo.isConnected();
	}
	
}
